#include "StdAfx.h"
#include "VNormalizedImage.h"
#include "Panel.h"


VNormalizedImage::VNormalizedImage(const VNormalizedImage& normImage){
	*this = normImage;
	//char * newBitmap = NULL;
	//if(normImage.bitmap != NULL)
	//	newBitmap = new char [normImage.newBitmapSize];
	//setBitmap(newBitmap);
	//newBitmapSize = normImage.newBitmapSize;
	//bitmap = NULL;
}
VNormalizedImage::VNormalizedImage(char * _bitmap, int _width, int _height, int _colorsPerPixel, int _bytePerColor, float _rescaleSlope /*= 1*/, int _rescaleIntercept /*= 0*/ , bool _colorPresentation/* = 0*/):
	bitmap(_bitmap)
	,width(_width)
	,height(_height)
	,colorsPerPixel(_colorsPerPixel)
	,bytePerColor(_bytePerColor)
	,rescaleSlope(_rescaleSlope)
	,rescaleIntercept(_rescaleIntercept)
	,colorPresentation(_colorPresentation)
	,oldBitmapSize(0)
	,isUpdated(false)
	,newBitmapSize(_width * _height * _colorsPerPixel * _bytePerColor)
	,offsetImage(0)
	{
	
	}

VNormalizedImage::VNormalizedImage(const VNormalizedImage& normImage, char * _bitmap, int * bitmapSrc,  int _width, int _height):
	bitmap(_bitmap)
	,width(_width)
	,height(_height)
	,colorsPerPixel(normImage.colorsPerPixel)
	,bytePerColor(normImage.bytePerColor)
	,rescaleSlope(normImage.rescaleSlope)
	,rescaleIntercept(normImage.rescaleIntercept)
	,colorPresentation(normImage.colorPresentation)
	,oldBitmapSize(0) 
	,isUpdated(false)
	,newBitmapSize(_width * _height * normImage.colorsPerPixel * normImage.bytePerColor)
	,offsetImage(0)
	{			
		for(int i = 0; i < width * _height * normImage.colorsPerPixel; i++)
			setValue( i, *(bitmapSrc + i));
	}

VNormalizedImage::VNormalizedImage():
	bitmap(NULL)
	,width(0)
	,height(0)
	,colorsPerPixel(1)
	,bytePerColor(1)
	,rescaleSlope(1)
	,rescaleIntercept(0)
	,colorPresentation(NULL)
	,oldBitmapSize(0)
	,isUpdated(false)
	,offsetImage(0){

}

		
VNormalizedImage::~VNormalizedImage(void){
		//delete bitmap;
	}

void VNormalizedImage::grabRegion(VNormalizedImage  * normalizedImageSrc, int x, int y, int widthSrc, int heightSrc, int widthDst, int heightDst){
	float a = (float)widthSrc / (float)widthDst;
	float b = (float)heightSrc / (float)heightDst;
	bytePerColor = normalizedImageSrc->bytePerColor;
	colorsPerPixel = normalizedImageSrc->colorsPerPixel;
	rescaleSlope = normalizedImageSrc->rescaleSlope;
	rescaleIntercept = normalizedImageSrc->rescaleIntercept;	
	colorPresentation = normalizedImageSrc->colorPresentation;
	bool needUpdate = false;	
	if(normalizedImageSrc != prevNormalizedImageSrc)
		needUpdate = true;
	else
		if(x != prevX || y != prevY)
			needUpdate = true;
	int sizeLine = normalizedImageSrc->width * bytePerColor * colorsPerPixel;
	QByteArray byteArray( normalizedImageSrc->bitmap + sizeLine * normalizedImageSrc->height / 2, sizeLine);
	if(byteArray != prevByteArray)
		needUpdate = true;
	int kQuality = 1;	
	float scaleX = 1;
	float scaleY = 1;	

	int signX =  - x * scaleX;	
	int signW = normalizedImageSrc->width * scaleX;
	int signY =  - y * scaleY;
	int signH =  normalizedImageSrc->height * scaleY;	

	int difX = 0;
	if(signX > 0){
		difX = signX;
		signX = 0;				
	}else{
		signX *= -1;
	}
	int difY = 0;
	if(signY > 0){
		difY = signY;
		signY = 0;
	}else{
		signY *= -1;
	}
	int signAX =  signX + normalizedImageSrc->width * scaleX;		
	int signAY =  signY + normalizedImageSrc->height * scaleY;	
	if(signAX > normalizedImageSrc->width * scaleX)
		signAX = normalizedImageSrc->width * scaleX;
	if(signAY > normalizedImageSrc->height * scaleY)
		signAY = normalizedImageSrc->height * scaleY;
	if(difX + signAX + signX > widthSrc * scaleX && signAX > widthSrc * scaleX - difX + signX)
		signAX = widthSrc * scaleX - difX + signX;
	if(difY + signAY + signY > heightSrc * scaleY && signAY > heightSrc * scaleY - difY + signY)
		signAY = heightSrc * scaleY - difY + signY;
	significantRect.setRect(signX, signY, signAX - signX, signAY - signY);	
	int signWidthDst = 0;
	int signHeightDst = 0;
	if((widthDst * heightDst >= widthSrc * heightSrc) || !Panel::isQuickly){
		widthDst = widthSrc;
		heightDst = heightSrc;
		while((signAX - signX) % 4 != 0)
			signAX --;		
		significantRect.setRect(signX, signY, signAX - signX, signAY - signY);	
		signWidthDst = significantRect.width();
		signHeightDst = significantRect.height();
		newBitmapSize = significantRect.width() * significantRect.height() * bytePerColor * colorsPerPixel;
			//newBitmapSize = widthDst * heightDst * bytePerColor * colorsPerPixel * 8;
			if(newBitmapSize > oldBitmapSize || bitmap == NULL){
				delete bitmap;
				bitmap = new char [newBitmapSize];	
				oldBitmapSize = newBitmapSize;
			}		

			signWidthDst = significantRect.width();
			signHeightDst = significantRect.height();
			normalizedImageSrc->copyRegionFromImage(bitmap, significantRect.left(), significantRect.top(), significantRect.width(), significantRect.height());	
	}else{	
		offsetImage = 0;
		widthDst = widthDst / kQuality;
		heightDst = heightDst / kQuality;		
		//while(widthDst % 4 != 0)
		//	widthDst ++;	
		scaleX = (float)widthDst / widthSrc;
		scaleY = (float)heightDst / heightSrc;
		scaleY = scaleX;
		signWidthDst = significantRect.width() * scaleX;
		signHeightDst = significantRect.height() * scaleY;
	//	signWidthDst *= scaleX;
	//	signHeightDst *= scaleY;
		while(signWidthDst % 4 != 0)
				signWidthDst --;
		if(needUpdate || width != widthDst || height != heightDst){
			//unsigned int newBitmapSize = widthDst * heightDst * bytePerColor * colorsPerPixel;
			newBitmapSize = signWidthDst * signHeightDst * bytePerColor * colorsPerPixel;
			if(newBitmapSize > oldBitmapSize || bitmap == NULL){
				delete bitmap;					
				bitmap = new char [newBitmapSize];
				oldBitmapSize = newBitmapSize;
			}				
			//normalizedImageSrc->ScaleNearest(bitmap, widthDst, heightDst, x,  y, widthSrc, heightSrc);
			normalizedImageSrc->ScaleNearest(bitmap, signWidthDst, signHeightDst, significantRect.left(), significantRect.top(), significantRect.width(), significantRect.height());				
		}
		
	}
	if(needUpdate)
		isUpdated = true;
	prevNormalizedImageSrc = normalizedImageSrc;
	prevByteArray = byteArray;
	width = widthDst;
	height = heightDst;
	this->prevX = x;
	this->prevY = y;	
	signX =  - x * scaleX;	
	//int signW = normalizedImageSrc->width * scaleX;
	signY =   - y * scaleY;
	signH =  normalizedImageSrc->height * scaleY;


	signAX =  signX + normalizedImageSrc->width * scaleX;		
	signAY =  signY + normalizedImageSrc->height * scaleY;	


	if(signX < 0)
		signX = 0;
	if(signY < 0)
		signY = 0;	
	
	if(signAX > widthSrc * scaleX)
		signAX = widthSrc * scaleX;
	if(signAY > heightSrc * scaleY)
		signAY = heightSrc * scaleY;
	significantRect.setRect(signX, signY, signWidthDst, signHeightDst);
	//significantRect.setRect(signX, signY, signW, signH);		
}

const void * VNormalizedImage::getBitmap()
{
	return (const void *)bitmap;
}


void VNormalizedImage::ScaleNearest(char * dist, int widthDst, int heightDst, int xDst, int yDst, int widthSrc, int heightSrc){	
	float scaleX = (float)widthDst / (float)widthSrc;
	float scaleY = (float)heightDst / (float)heightSrc;
	char * sourse = (char *)bitmap;	
	int fullSizeImage =  height * width * colorsPerPixel;
	int offsetDsti = 0;
	int offsetSrci = 0;
	for(int i = 0; i < heightDst ; i++){
		int iSrc = (int) (i / scaleY);
		offsetDsti = widthDst * i * colorsPerPixel;
		offsetSrci = width * (iSrc + yDst) * colorsPerPixel;
		for(int j = 0; j < widthDst; j++){		   
		   for(int h = 0; h < colorsPerPixel; h++){			  
			   int jj = (int) ((j + 0) / scaleX);			 
			   if((iSrc + yDst <= 0 || iSrc + yDst >= height || xDst + jj <= 0 || xDst + jj >= width) ||
				   (offsetSrci + jj * colorsPerPixel + xDst * colorsPerPixel + h >= fullSizeImage)){				
				}else{
					if(bytePerColor == 1)
						*((unsigned char *)dist + offsetDsti + j * colorsPerPixel + h) = 
						*((unsigned char *)sourse + offsetSrci + jj * colorsPerPixel + xDst * colorsPerPixel + h);
					if(bytePerColor == 2){					
						*((unsigned short *)dist + offsetDsti + j * colorsPerPixel + h) = 
						*((unsigned short *)sourse + offsetSrci + jj * colorsPerPixel + xDst * colorsPerPixel + h);
					}
					if(bytePerColor == 4)
						*((unsigned int *)dist + offsetDsti + j * colorsPerPixel + h) = 
						*((unsigned int *)sourse + offsetSrci + jj * colorsPerPixel + xDst * colorsPerPixel + h);					
				}
		   }
		}
	}
}


void VNormalizedImage::copyRegionFromImage(char * dst, int left, int top, int width, int height){
	width = width * colorsPerPixel * bytePerColor;  	
	left *= colorsPerPixel * bytePerColor; 	
	char * pSrcImage = bitmap;	
	for(int i = 0; i < height ; i ++){		
		memcpy(dst + width * i , pSrcImage + this->width * colorsPerPixel * bytePerColor * (i + top) + left , width); //this->height - height
	}	
	return;
}


/*
void VNormalizedImage::copyRegionFromImage(char * dst, int left, int top, int newWidth, int newHeight){
	int width = this->width * colorsPerPixel;  
	newWidth *= colorsPerPixel;
	left *= colorsPerPixel; 	
	char * pSrcImage = bitmap;	
	for(int i = 0; i < newHeight ; ++i){
	   if(i + top < 0 || i + top >= height){	
			  // memcpy(imageBufferRegion + (newWidth * i * sizePixel), lineBuffer, newWidth * sizePixel);
	   }else{
		   if(left < 0){
				//memcpy(imageBufferRegion + (newWidth * i * sizePixel) , lineBuffer, - left * sizePixel);
				if(newWidth + left > width){
					memcpy(dst + (newWidth * i - left) * bytePerColor, pSrcImage + width * (i + top) * bytePerColor , width * bytePerColor);
				}else{
					memcpy(dst + (newWidth * i - left) * bytePerColor, pSrcImage + width * (i + top) * bytePerColor, (newWidth + left) * bytePerColor);
				}
		   }else{			  
			   if(newWidth + left > width){

				   memcpy(dst + (newWidth * i * bytePerColor), pSrcImage + ((width * (i + top) + left) * bytePerColor), (width - left) * bytePerColor);
			   }else{
					memcpy(dst + (newWidth * i * bytePerColor), pSrcImage + ((width * (i + top) + left) * bytePerColor), newWidth * bytePerColor);
			   }
		   }	   
		  // if(newWidth > width - left){	
			//	memcpy(imageBufferRegion + (newWidth * i - left  + width) * sizePixel, lineBuffer, (newWidth - (width - left)) * sizePixel);		   
		   //}
	   }
	}	
	return;
}*/


int VNormalizedImage::getWidth()
{
	return width;
}

int VNormalizedImage::getHeight()
{
	return height;
}

int VNormalizedImage::getColorsPerPixel()
{
	return colorsPerPixel;
}

int VNormalizedImage::getBytePerColor()
{
	return bytePerColor;
}
int VNormalizedImage::getValue( unsigned int offset ){
	void * pixel;  
	int value;
	/*
	int y = offset / width;
	int x = offset - y * width;
	if(x < significantRect.left() || x > significantRect.right() || y < significantRect.top() || y > significantRect.bottom())
		return 0;	
	int newY = y - significantRect.top();
	int newX = x - significantRect.left();
	if(newY == 510){
		int a = 4;
	}
	*/
	//offset = newY * significantRect.width() + newX;	
	if(colorPresentation && colorsPerPixel == 1){
		if(bytePerColor == 1){					   
			pixel = ((char *)bitmap + offset);					  
			value = *(char *)pixel;					  
		}
		if(bytePerColor == 2){
			pixel = ((short *)bitmap + offset);
			value = *(short *)pixel;					   
		}
		if(bytePerColor == 4){
			pixel = ((int *)bitmap + offset);
			value = *(int *)pixel;					   
		}
	}else{
		if(bytePerColor == 1){
			pixel = ((unsigned char *)bitmap + offset);
			value = *(unsigned char *)pixel;					  
		}
		if(bytePerColor == 2){
			pixel = ((unsigned short *)bitmap + offset);
			value = *(unsigned short *)pixel;					   
		}
		if(bytePerColor == 4){
			pixel = ((unsigned int *)bitmap + offset);
			value = *(unsigned int *)pixel;					  
		}
	}	
	if(rescaleSlope != 0)
		value = value* rescaleSlope + rescaleIntercept;

	return value;
		
}

void VNormalizedImage::setValue( unsigned int offset, int value){	
	//int value;
	if(rescaleSlope != 0)
		value = (value - rescaleIntercept) / rescaleSlope;
	if(colorPresentation && colorsPerPixel == 1){
		if(bytePerColor == 1){	
			char pixel = value;		
			*((char *)bitmap + offset) = pixel;					  						  
		}
		if(bytePerColor == 2){
			short pixel = value;		
			*((short *)bitmap + offset) = pixel;				   
		}
		if(bytePerColor == 4){
			int pixel = value;		
			*((int *)bitmap + offset) = pixel;			   
		}
	}else{
		if(bytePerColor == 1){
			*((unsigned char *)bitmap + offset) = value;			
		}
		if(bytePerColor == 2){
			*((unsigned short *)bitmap + offset) = value;				   
		}
		if(bytePerColor == 4){
			*((unsigned int *)bitmap + offset) = value;
						  
		}
	}	
}

void VNormalizedImage::setBitmap( char * bitmap )
{
	this->bitmap = bitmap;
}

void VNormalizedImage::setBitmap( char * bitmap, int width, int height )
{
	this->bitmap = bitmap;
	this->width = width;
	this->height = height;
}

void VNormalizedImage::setBitmap( char * bitmap, int width, int height, int colorsPerPixel, int bytePerColor, float rescaleSlope /*= 1*/, int rescaleIntercept /*= 0*/ )
{
	/*	this->bitmap = bitmap;
		this->width = width;
		this->height = height;
		this->colorsPerPixel = colorsPerPixel;
		this->bytePerColor = bytePerColor;
		this->rescaleSlope = rescaleSlope;
		this->rescaleIntercept = rescaleIntercept;
		this->colorPresentation = colorPresentation;
		this->oldBitmapSize = oldBitmapSize;
		*/
}

bool VNormalizedImage::operator==( const VNormalizedImage& other ) const
{
	int a = 4;
	if( this->bitmap == other.bitmap &&
		this->width == other.width &&
		this->height == other.height &&
		this->bytePerColor == other.bytePerColor &&
		this->colorsPerPixel == other.colorsPerPixel &&
		this->prevX == other.prevX &&
		this->prevY == other.prevY &&
		this->prevByteArray == prevByteArray)
		return true;
	else
		return false;
}

bool VNormalizedImage::operator!=( const VNormalizedImage& other ) const
{
	return !operator==(other); 
}